﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Text;
using System.Threading.Tasks;

namespace SharpSoft.Maths.Gestures
{
    /// <summary>
    /// 手势管理
    /// </summary>
    public class GesturesManager
    {
        private object asyncState = new object();
        private List<ValueTuple<Vector2, Vector2, DateTime>> history = new List<ValueTuple<Vector2, Vector2, DateTime>>();
        ValueTuple<Vector2, Vector2, DateTime> lastFrame;

        /// <summary>
        /// 手势最少的持续时间
        /// </summary>
        public TimeSpan MinVaryingTime { get; set; } = TimeSpan.FromSeconds(0.2);
        public TimeSpan MaxVaryingTime { get; set; } = TimeSpan.FromSeconds(2);
        /// <summary>
        /// 最小的偏移
        /// </summary>
        public float MinDistance { get; set; } = 50f;
        /// <summary>
        /// 推送帧
        /// </summary>
        /// <param name="point"></param>
        /// <param name="time"></param>
        public void PushFrame(Vector2 point, DateTime time)
        {
            var v = point - lastFrame.Item1;
            ValueTuple<Vector2, Vector2, DateTime> cur = new ValueTuple<Vector2, Vector2, DateTime>(point, v, time);
            lastFrame = cur;
            lock (asyncState)
            {
                history.Add(cur);
            }
            calcTendency();
        }
        /// <summary>
        /// 清除历史记录
        /// </summary>
        public void ClearHistory()
        {
            lock (asyncState)
            {
                history.Clear();
            }
            lastFrame = new ValueTuple<Vector2, Vector2, DateTime>();
        }

        /// <summary>
        /// 计算趋势
        /// </summary>
        private void calcTendency()
        {
            float xfoward = 0, yfoward = 0;
            bool xchanged = false, ychanged = false;
            if (history.Count <= 3)
            {
                return;
            }

            var first = history[0];
            var last = history[history.Count - 1];
            if (last.Item3 - first.Item3 > MaxVaryingTime)
            {//超过了最大时间
                this.ClearHistory();
                return;
            }
            lock (asyncState)
            {
                foreach (var item in history)
                {
                    var x = item.Item2.X;
                    var y = item.Item2.Y;
                    if (xfoward != 0f)
                    {
                        if (xfoward * x < 0)
                        {
                            xchanged = true;
                        }
                        if (yfoward * y < 0)
                        {
                            ychanged = true;
                        }
                    }

                    xfoward = x;
                    yfoward = y;
                }
            }
            if (!xchanged)
            {
                if (last.Item3 - first.Item3 < MinVaryingTime)
                {//尚未达到最小时间
                    return;
                }
                var dis = (last.Item1 - first.Item1).Length();
                if (MathF.Abs(dis) < MinDistance)
                {
                    //尚未达到最小距离
                    return;
                }
                this.ClearHistory();
                this.OnSwipe(SwipeOrientation.Horizontal, last.Item1.X - first.Item1.X);
            }
            else
            {//期间方向变了
                this.ClearHistory();
            }
            //if (!ychanged)
            //{

            //}
        }
        protected void OnSwipe(SwipeOrientation ori, float dis)
        {
            SwipeEventArgs e = new SwipeEventArgs() { Orientation = ori, Distance = dis };
            Swipe?.Invoke(this, e);
        }

        public event SwipeEventHandler Swipe;
    }

    public delegate void SwipeEventHandler(object sender, SwipeEventArgs e);
    public class SwipeEventArgs : EventArgs
    {
        public SwipeOrientation Orientation { get; set; }
        public float Distance { get; set; }
    }

    public enum SwipeOrientation
    {
        Horizontal,
        Vertical
    }
}
